import 'dart:math';

import 'package:flutter/material.dart';

import 'shape.dart';

enum DxDiagonalPosition { bottom, top, left, right }

enum DxDiagonalDirection { left, right }

/// 斜线
class DxDiagonalShape extends Shape {
  final DxDiagonalPosition position;
  final DxDiagonalDirection direction;
  final double? angle;

  DxDiagonalShape({this.position = DxDiagonalPosition.bottom, this.direction = DxDiagonalDirection.left, this.angle});

  @override
  Path build({Rect? rect, double? scale}) => generatePath(rect: rect!);

  Path generatePath({required Rect rect}) {
    final Path path = Path();

    final width = rect.width;
    final height = rect.height;

    final $angle =
        angle != null ? _DxDiagonalAngle.deg(angle: angle!) : const _DxDiagonalAngle.radians(angle: pi / -20);
    final double diagonalAngleRadAbs = $angle.angleRadians.abs();
    final bool isDirectionLeft = direction == DxDiagonalDirection.left;
    final double perpendicularHeight = (rect.width * tan(diagonalAngleRadAbs));

    switch (position) {
      case DxDiagonalPosition.bottom:
        if (isDirectionLeft) {
          path.moveTo(0, 0);
          path.lineTo(width, 0);
          path.lineTo(width, height - perpendicularHeight);
          path.lineTo(0, height);
          path.close();
        } else {
          path.moveTo(width, height);
          path.lineTo(0, height - perpendicularHeight);
          path.lineTo(0, 0);
          path.lineTo(width, 0);
          path.close();
        }
        break;
      case DxDiagonalPosition.top:
        if (isDirectionLeft) {
          path.moveTo(width, height);
          path.lineTo(width, 0 + perpendicularHeight);
          path.lineTo(0, 0);
          path.lineTo(0, height);
          path.close();
        } else {
          path.moveTo(width, height);
          path.lineTo(width, 0);
          path.lineTo(0, 0 + perpendicularHeight);
          path.lineTo(0, height);
          path.close();
        }
        break;
      case DxDiagonalPosition.right:
        if (isDirectionLeft) {
          path.moveTo(0, 0);
          path.lineTo(width, 0);
          path.lineTo(width - perpendicularHeight, height);
          path.lineTo(0, height);
          path.close();
        } else {
          path.moveTo(0, 0);
          path.lineTo(width - perpendicularHeight, 0);
          path.lineTo(width, height);
          path.lineTo(0, height);
          path.close();
        }
        break;
      case DxDiagonalPosition.left:
        if (isDirectionLeft) {
          path.moveTo(0 + perpendicularHeight, 0);
          path.lineTo(width, 0);
          path.lineTo(width, height);
          path.lineTo(0, height);
          path.close();
        } else {
          path.moveTo(0, 0);
          path.lineTo(width, 0);
          path.lineTo(width, height);
          path.lineTo(0 + perpendicularHeight, height);
          path.close();
        }
        break;
    }
    return path;
  }
}

class _DxDiagonalAngle {
  final double angleRadians;

  const _DxDiagonalAngle.radians({double angle = 0}) : angleRadians = angle;

  _DxDiagonalAngle.deg({double angle = 0}) : this.radians(angle: angle * (pi / 180.0));

  @override
  bool operator ==(Object other) =>
      identical(this, other) ||
      other is _DxDiagonalAngle && runtimeType == other.runtimeType && angleRadians == other.angleRadians;

  @override
  int get hashCode => angleRadians.hashCode;
}
